/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Compass;

import java.io.IOException;
import java.util.*;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;
import javax.microedition.location.*;
import javax.microedition.io.file.*;
import javax.microedition.io.*;

      

public class Compass extends MIDlet {
    private static final String[] courseList =
        {"N", "NNE", "NE", "NEE", "E", "SEE", "SE", "SSE", "S", "SSW", "SW", "SWW", "W", "NWW", "NW", "NNW"};

    Display display;
    VideoCanvas canvas;
   
    public Compass() {
        canvas = new VideoCanvas(this);
        display = Display.getDisplay(this);

    }

    public void startApp() {
        display.setCurrent( canvas );
    }

    public void pauseApp() {}

    public void destroyApp(boolean unconditional) {}

    public void vibrate()
    {
        display.vibrate(50);
    }

    public void close()
    {
        display.setCurrent(null);
        display=null;
        destroyApp(true);
        notifyDestroyed();
    }
    
   class VideoCanvas extends Canvas implements LocationListener {
    LocationProvider locationProvider;
    Orientation compass;
    String compasserr=null;
    private Compass midlet;
    Image rose, neuImg, theSun;
    Timer timer;
    int w,h,nw,nh,bw,bh,sunw,sunh,i,index;
    int rgbZeiger[], neu[];
    float scalew, scaleh;
    double course,lastangle,lastcourse;
    MenuBar menubar;
       
    public VideoCanvas(Compass m) {
        menubar = new MenuBar("Compass");

        midlet=m;
        setFullScreenMode(true);
        locationProvider=null;
        
        course = lastcourse = -1; i=0; lastangle=0;
        if (createLocator()) course=-0.01;
        /*  try {
            FileConnection f = (FileConnection) Connector.open("file:///filesystem/compass_bg.jpg", Connector.READ);
            rose = Image.createImage(f.openInputStream());
         } catch (Exception e) { rose = null;}
         try { if (rose==null) rose = Image.createImage ( "/compass_bg.jpg" );
         } catch (Exception e) { rose = null;}
         */
               
        bw = rose==null ? 0 : rose.getWidth();
        bh = rose==null ? 0 : rose.getHeight();
        
        
        nw = nh = 167;
        neu = new int[nw*nh];
        rgbZeiger = new int[480*480];
        loadRose();
        loadSun();

        rotate();
        repaint();

        timer = new Timer();
        timer.schedule(new updateTask(this), 0, 80);

   //     timer2 = new Timer();
     //   timer2.schedule(new captureTask(this), 0, 4000);
    }
/*
    class captureTask extends TimerTask {
        private VideoCanvas canvas;
        private int shot = 1000;

        captureTask( VideoCanvas c ){ canvas = c; }
        public void run() {
            Image img = Image.createImage(240,400);
            canvas.paint(img.getGraphics());
            int rgb[] = new int[240*400];
            byte rgbb[] = new byte[240*400*3];
            img.getRGB(rgb, 0,240,0,0,240,400);
            shot++;
            for ( int i=0,j=0; i<240*400; i++ )
            {   int col=rgb[i];
                for ( int n=0; n<3; n++ ) { rgbb[j++]=(byte)(col&0xff); col>>=8; }
            }
            try{
                FileConnection f = (FileConnection) Connector.open("file:///mmc/Screenshot" + shot +".raw");
                f.create();
                f.openDataOutputStream().write(rgbb, 0, 240*400*3);
                f.close();
            } catch( Exception e ) { ; }

        }
    }
*/


    class updateTask extends TimerTask {
        private VideoCanvas canvas;
        updateTask( VideoCanvas c ){  canvas = c;  }
        public void run() {
            // correct course
            if ( (course-lastcourse)>180 ) lastangle+=360; else
            if ( (course-lastcourse)<-180 ) lastangle-=360;
            lastcourse=course;

            double diff = Math.abs(lastangle-course);
            boolean updated = false;

            updated |= menubar.update();

            if (menubar.feedback) { midlet.vibrate(); menubar.feedback=false; }
            
            if (diff>0.1)
            {
                lastangle = lastangle*0.95 + course*0.05;
                canvas.rotate();
                updated |= true;

            }

            if (updated)
                canvas.repaint();

        }
    }


    public boolean createLocator()
    {
        Criteria crit = new Criteria ();
        crit.setPreferredResponseTime(Criteria.NO_REQUIREMENT);
        crit.setPreferredPowerConsumption(Criteria.NO_REQUIREMENT);
        crit.setHorizontalAccuracy(100);
        crit.setVerticalAccuracy(100);
        crit.setSpeedAndCourseRequired(true);
        //crit.setCostAllowed(false);
        try {
            locationProvider = LocationProvider.getInstance(crit);
            locationProvider.setLocationListener(this, 1, 1, 1);
        }
        catch (LocationException le) {
            locationProvider = null;
        }


        /*
        try {
            compass = Orientation.getOrientation();
        } catch(LocationException e) { compasserr="no compass"; compass=null;}
        catch(SecurityException e) { compasserr="access rights"; compass=null;}
        */
        return locationProvider!=null;
    }

    public void loadRose()
    {
        if (rose==null) {
            try {
                FileConnection f = (FileConnection) Connector.open("file:///filesystem/compass_bg.jpg", Connector.READ);
                rose = Image.createImage(f.openInputStream());
            } catch (Exception e) { rose = null;}
            try { if (rose==null) rose = Image.createImage ( "/compass_bg.jpg" );
            } catch (Exception e) { rose = null;}
            bw = rose==null ? 0 : rose.getWidth();
            bh = rose==null ? 0 : rose.getHeight();
        }

        Image zeiger=null;
        try {
            FileConnection f = (FileConnection) Connector.open("file:///filesystem/compass_rose"+(index+1)+".jpg",Connector.READ);
            zeiger = Image.createImage(f.openInputStream());
        } catch (Exception e) { zeiger=null;}

        if (zeiger==null && index>0)
        {
            index=0;
            try {
                FileConnection f = (FileConnection) Connector.open("file:///filesystem/compass_rose1.jpg",Connector.READ);
                zeiger = Image.createImage(f.openInputStream());
            } catch (Exception e) { zeiger=null;}
        }
        if (zeiger==null) try{
            zeiger = Image.createImage ( "/compass_rose1.jpg" );
        } catch (IOException e) { zeiger=null;}

        if (zeiger!=null)
        try {
            w = zeiger.getWidth();
            h = zeiger.getHeight();
            if (w<=480 && h<=480)
                zeiger.getRGB(rgbZeiger, 0, w, 0,0,w,h);

            // mask dark out!
            int c;
            for ( int i=0; i<w*h; i++ )
            {
                c=rgbZeiger[i];
                c=(c&0xff) + ((c>>1)&0xff) + ((c>>16)&0xff);

                if (c<10) rgbZeiger[i]=0; else
                if (c<138) rgbZeiger[i]=(rgbZeiger[i]&0xffffff)+(((c-10)*2)<<24); // blend out!
            }

            scalew = ((float)w/(float)nw);
            scaleh = ((float)h/(float)nh);
        }
        catch (Exception e) { w=h=0;}
    }

    public void loadSun()
    {
        Image sun = null;
       /*try {
            FileConnection f = (FileConnection) Connector.open("file:///filesystem/compass_sunflare.png");
            if (f.exists()) sun = Image.createImage(f.openInputStream());
        } catch (IOException e) { sun=null; }
*/
        if (sun==null) try { sun = Image.createImage ( "/compass_sunflare.png" ); } catch (Exception e) { sun=null; }

        if (sun!=null)
        try {
            sunw = sun.getWidth();
            sunh = sun.getHeight();
            int rgb[] = new int[sunw*sunh];
            sun.getRGB(rgb, 0, sunw, 0,0,sunw,sunh);
            for ( int i=0; i<sunw*sunh; i++ ) rgb[i]=((rgb[i]&0xff)<<24)+0xffffd0;
            theSun = Image.createRGBImage(rgb, sunw, sunh, true);
        } catch (Exception e) { theSun=null; sunw=sunh=0; }
    }

    public void rotate( )
    {
        float b = (float)Math.sin(((-lastangle-45)*Math.PI)/180.0);
        float a = (float)Math.cos(((-lastangle-45)*Math.PI)/180.0);
        float ry, rx, mx=((float)w)/2, my=((float)h)/2, nx=((float)nw)/2, ny=((float)nh)/2; int ox, oy;
        for ( int y=0,z=0; y<nh; y++ )
        {
            ry = (float)y-ny;
            for ( int x=0; x<nw; x++,z++ )
            {
                rx = (float)x-nx;
                ox = (int)((a*rx+b*ry)*scalew+mx);
                if (ox>=0 && ox<w) {
                   oy = (int)((-b*rx+a*ry)*scaleh+my);
                   if (oy>=0 && oy<h) neu[z] = rgbZeiger[ox+oy*w];
                } else
                neu[z] = 0;
            }
        }
        neuImg = Image.createRGBImage(neu, nw, nh, true);
    }

    public void paint(Graphics g) {
        int width = getWidth();
        int height = getHeight();
        int y0 = (height-400)/2;
        String grad = "";
        g.drawImage(rose,(width-bw)/2,(height-bh)/2+y0,0);
        g.drawImage(neuImg,(width-nw)/2,(height-nh)/2+y0,0);
        g.setColor(0xffffff);
        g.setFont( Font.getFont( Font.FACE_PROPORTIONAL, Font.STYLE_BOLD, Font.SIZE_LARGE) );

        if (course>=0)
        {
            grad = new Integer((int)course).toString() + "° " + courseList[(int)((course+360.0)/(360.0/16.0)+0.5)%16];
            g.drawString(grad,(240-g.getFont().stringWidth(grad))/2,50,0);
        }
        if (compasserr!=null) g.drawString(compasserr,(240-g.getFont().stringWidth(compasserr))/2,height-60,0);
        
        Calendar c = Calendar.getInstance();
        double sun = (double)(c.get(Calendar.HOUR_OF_DAY)*60 + c.get(Calendar.MINUTE))/4.0;
        sun = ((sun-lastangle)*Math.PI)/180;
        g.setColor(0xffff80);
        
        int sunx = (int)(Math.sin(sun)*(16+nw/2) + width/2);
        int suny = (int)(-Math.cos(sun)*(16+nh/2) + height/2);
        if (theSun!=null) g.drawImage(theSun, sunx-sunw/2, suny-sunh/2, 0);
        g.fillArc( sunx-2, suny-2+y0,4,4,0,360);
        menubar.paint(g);
    }

    public void pointerPressed( int x, int y )
    {
        if (!menubar.pointerPressed(x,y));
       /* {
            index = (index+1)%3;
            loadRose();
            rotate(); repaint();
        }*/
       // course -= 84; if (course>=360) course-=360; if (course<0) course+=360;
    }

    public void pointerDragged( int x, int y )
    {
        menubar.pointerDragged(x,y);
    }

    public void pointerReleased( int x, int y )
    {
        if (menubar.exitPushed && menubar.charged) midlet.close();
        if (menubar.menuPushed && menubar.charged) { index = (index+1)%3; loadRose(); rotate(); repaint(); }
        menubar.pointerReleased(x,y);
    }

    public void locationUpdated( LocationProvider p, final Location loc ) {
        QualifiedCoordinates c = loc.getQualifiedCoordinates();
        float course0 = loc.getCourse();
        if (course0!=0) course = course0;
     //   String nmeaStr = loc.getExtraInfo("application/X-jsr179-location-nmea");
     //   if (nmeaStr!=null) compasserr = nmeaStr;
/*
        try {
            compass = Orientation.getOrientation();
        } catch(LocationException e) { compasserr="no compass"; compass=null;}
        catch(SecurityException e) { compasserr="access rights"; compass=null;}
*/    }

    public void providerStateChanged( LocationProvider p, final int _state ) {
     //   if (p.getState()!=LocationProvider.AVAILABLE) lastUpdate=0;
    }
   
   }
}